﻿using Kairos.Migrations;
using Kairos.Properties;
using System;
using System.Collections.Generic;
using System.Data.Entity.Migrations;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Principal;
using System.Web;
using System.Web.Routing;

namespace Kairos
{
    [Flags]
    public enum Roles
    {
        All = Administrator | Worker | Reader,

        Reader = 1,
        Worker = 2,
        Administrator = 4
    }

    public static class Utilities
    {
        public static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
        public static readonly string AssemblyName = Assembly.GetName().Name;

        public static readonly string ConfigurationFolder = "Configuration";

        public static readonly string CollationAnnotationName = "Collation";

        public static readonly string CookieNameVtomJobsFilter = "VtomJobsFilter";
        public static readonly string CookieNameGraphesSearchstring = "GraphesSearchstring";
        public static readonly string CookieNameDocsSearchstring = "DocsSearchstring";

        public static readonly string WindowsGroupPrefixSetting = "WindowsGroup";

        [Conditional("DEBUG")]
        internal static void DbUpdate()
        {
            var configuration = new Configuration();
            var migrator = new DbMigrator(configuration);
            migrator.Update();
        }

        public static bool IsInAnyRole(this IPrincipal user, Roles candidates)
        {
            if (user == null)
                return false;

            IEnumerable<Roles> DefaultRoles = Enum.GetValues(typeof(Roles))
                .OfType<Roles>()
                .Where(r => r != Roles.All)
                .Where(r => candidates.HasFlag(r));

            foreach (var role in DefaultRoles)
            {
                var candidate = Settings.Default[string.Concat(WindowsGroupPrefixSetting, role.ToString())].ToString();

                if (user.IsInRole(candidate))
                    return true;
            }

            return false;
        }

        public static RouteValueDictionary GetQuerystring(this string querystring)
        {
            RouteValueDictionary values = new RouteValueDictionary();

            if (querystring == null)
                return values;

            var querystrings = HttpUtility.ParseQueryString(querystring);

            foreach (string s in querystrings.AllKeys)
                values.Add(s, querystrings[s]);

            return values;
        }
        public static RouteValueDictionary AddRange(this RouteValueDictionary first, RouteValueDictionary second)
        {
            if (first == null)
                throw new ArgumentNullException("first");

            if (second == null)
                throw new ArgumentNullException("second");

            RouteValueDictionary result = new RouteValueDictionary();

            foreach (var pair in first)
                result.Add(pair.Key, pair.Value);

            foreach (var pair in second)
                result.Add(pair.Key, pair.Value);

            return result;
        }

        #region Manifest resources from this assembly

        internal static string GetResourcePath(params string[] fragments)
        {
            if (fragments.First().StartsWith(Utilities.AssemblyName, StringComparison.Ordinal))
                if (string.Join(".", fragments).StartsWith(string.Join(".", Utilities.AssemblyName, Utilities.ConfigurationFolder), StringComparison.Ordinal))
                    return string.Join(".", string.Join(".", fragments));
                else
                    return string.Join(".", Utilities.ConfigurationFolder, string.Join(".", fragments));
            else
                if (fragments.First().StartsWith(Utilities.ConfigurationFolder, StringComparison.Ordinal))
                    return string.Join(".", Utilities.AssemblyName, string.Join(".", fragments));
                else
                    return string.Join(".", Utilities.AssemblyName, Utilities.ConfigurationFolder, string.Join(".", fragments));
        }

        internal static byte[] ExtractFromAssembly(string resource)
        {
            byte[] buffer;

            using (Stream input = Assembly.GetManifestResourceStream(GetResourcePath(resource)))
            {
                buffer = new byte[input.Length];
                input.Read(buffer, 0, buffer.Length);
            }
            return buffer;
        }

        internal static T ExtractFromAssembly<T>(string resource) where T : Stream
        {
            return (T)Utilities.Assembly.GetManifestResourceStream(GetResourcePath(resource));
        }

        public static IEnumerable<string> EnumerateFromAssembly(string path)
        {
            return Utilities.Assembly.GetManifestResourceNames().Where(s => s.StartsWith(GetResourcePath(path), StringComparison.Ordinal));
        }

        #endregion
    }
}